/*

	Copyright 2011 Etay Meiri

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef TECHNIQUE_H
#define	TECHNIQUE_H

#include <list>
#include <GL/glew.h>
#include <glm/glm.hpp>

class Technique
{
public:

    Technique();

    virtual ~Technique();

    virtual bool Init();

    void Enable();

protected:

    bool Finalize();

    GLint GetUniformLocation(const char* pUniformName);
    
    GLint GetProgramParam(GLint param);
    
    GLuint m_shaderProg;    

protected:

	bool AddShader(GLenum ShaderType, const char* pFilename);
    
private:

    typedef std::list<GLuint> ShaderObjList;
    ShaderObjList m_shaderObjList;
};

class MeshCutTechnique: public Technique
{
public:
	bool Init(){
		if (!Technique::Init()){
			return false;
		}
		if (AddShader(GL_VERTEX_SHADER, "../cut.vert")
			&& AddShader(GL_FRAGMENT_SHADER, "../cut.frag")
			&& Finalize())
		{
			gWVP = GetUniformLocation("gWVP");
			gColor = GetUniformLocation("gColor");
			gClipPlane = GetUniformLocation("gClipPlane");
			gWorld = GetUniformLocation("gWorld");
			
			return 
				gWVP != -1
				&& gColor != -1
				&& gClipPlane !=-1
				&& gWorld != -1
				;
		}
		else
		{
			return false;
		}
	}
	void setWVP(const glm::mat4& wvp){
		glUniformMatrix4fv(gWVP, 1, GL_TRUE, &wvp[0][0]);
	}
	void setColor(const glm::vec3& color){
		glUniform3fv(gColor, 1, &color[0]);
	}
	void setClipPlane(const glm::vec4& clipPlane){
		glUniform4fv(gClipPlane, 1, &clipPlane[0]);
	}
	void setWorld(const glm::mat4& world){
		glUniformMatrix4fv(gWorld, 1, GL_TRUE, &world[0][0]);
	}
private:
	GLuint gWVP;
	GLuint gColor;
	GLuint gClipPlane;
	GLuint gWorld;
};

class SimpleTechnique : public Technique
{
public:
	bool Init(){
		if (!Technique::Init()){
			return false;
		}
		if (AddShader(GL_VERTEX_SHADER, "../simple.vert")
			&& AddShader(GL_FRAGMENT_SHADER, "../simple.frag")
			&& Finalize())
		{
			gWVP = GetUniformLocation("gWVP");
			gColor = GetUniformLocation("gColor");
			gWorld = GetUniformLocation("gWorld");

			return
				gWVP != -1
				&& gColor != -1
				&& gWorld != -1
				;
		}
		else
		{
			return false;
		}
	}
	void setWVP(const glm::mat4& wvp){
		glUniformMatrix4fv(gWVP, 1, GL_TRUE, &wvp[0][0]);
	}
	void setColor(const glm::vec3& color){
		glUniform3fv(gColor, 1, &color[0]);
	}
	void setWorld(const glm::mat4& world){
		glUniformMatrix4fv(gWorld, 1, GL_TRUE, &world[0][0]);
	}
private:
	GLuint gWVP;
	GLuint gColor;
	GLuint gWorld;
};

#endif	/* TECHNIQUE_H */

